let _Vue = null
export default class VueRouter {
  static install (Vue) {
    // 1.判断当前插件是否已经被安装
    if (VueRouter.install.installed) {
      return
    }
    VueRouter.install.installed = true
    // 2.把Vue构建函数记录到全局变量
    _Vue = Vue
    // 3.把创建Vue实例时候传入的router对象注入到vue实例上
    // _Vue.prototype.$router = this.$options.router //这里this 指向VueRouter类，$ 是在 Vue 所有实例中都可用的属性的一个简单约定。这样做会避免和已被定义的数据、方法、计算属性产生冲突
    // 混入
    _Vue.mixin({ // 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时，所有混入对象的选项将被混入该组件本身的选项。
      // 创建beforeCreate()函数,这里面的this指向就是vue
      beforeCreate () { // beforeCreate为vue初始化过程中第一个钩子函数
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router // 通过在原型上定义它们使其在每个 Vue 的实例中可用
          // 调用初始化方法
          this.$options.router.init()
        }
      }
    })
  }

  constructor (options) {
    this.options = options
    this.routeMap = {}
    this.data = _Vue.observable({ // observable()方法，用于设置监控属性，这样就可以监控viewModule中的属性值的变化，从而就可以动态的改变某个元素中的值，监控属性的类型不变量而是一个函数，通过返回一个函数给viewModule对象中的属性，从而来监控该属性。
      current: '/' /// 存储当前路由地址
    })
  }

  init () {
    this.createRouteMap()
    this.initComponents(_Vue)
    this.initEvent()
  }

  createRouteMap () {
    // 遍历所有的路由规则，把路由规则解析成键值对的形式 存储到routeMap中
    this.options.routes.forEach(route => {
      this.routeMap[route.path] = route.component
    })
  }

  // router-link组件 to 变成 a 标签
  // 插槽 slot router-link内的内容替换slot 标签
  // render 替代template 不用在项目根目录创建vue.config.js ，h函数创建虚拟DOM
  // vue里的 component函数提交组件，第一个参数为组件的名称，第二个参数是一个注册组件的对象
  // render函数（渲染函数），渲染函数结合数据生成Virtual DOM树，Diff和Patch后生成新的UI
  // render 第一个参数是标签名类型必须是String
  // 第二个是属性值 我们后面来讲，类型是Object
  // 第三个是子级虚拟节点 (VNodes) 可以是String|Array
  initComponents (Vue) {
    Vue.component('router-link', {
      props: {
        to: String
      },
      render (h) {
        return h('a', {
          attrs: {
            href: '#' + this.to // 这里实现hash 模式
            // href: +this.to // 不用拼#号，这里实现history 模式
          },
          on: {
            click: this.clickHandler
          }
        }, [this.$slots.default]) // 获取默认插槽的内容
      },
      methods: {
        clickHandler (e) {
          // history.pushState({}, '', this.to) // 这里实现history 模式
          window.location.hash = this.to // 这里实现hash 模式
          this.$router.data.current = this.to
          e.preventDefault()
        }
      }
      // template: '<a :href="to"><slot></slot></a>'
    })
    const self = this // 将initComponents 的this（这this指向VueRouter对象） 存储到 self里
    Vue.component('router-view', {
      render (h) { // 将render方法中的this，改成self
        // self.data.current当前的路由地址
        const component = self.routeMap[self.data.current]
        return h(component)
      }
    })
  }

  initEvent () {
    // window.addEventListener('popstate', () => {
    //   this.data.current = window.location.pathname
    // })
    // 当路径变化之后，重新获取当前路径并记录到 current
    window.addEventListener('hashchange', this.onHashChange.bind(this))
    window.addEventListener('load', this.onHashChange.bind(this))
  }

  onHashChange () {
    this.data.current = window.location.hash.substr(1) || '#/'
  }
}
